﻿//**********************************************************
//Copyright(C)2010 By 波特商网公司 版权所有。
//
//文件名：
//文件功能：日期控件
//
//创建标识：米海波 || 2011-04-12
//
//修改标识：
//修改描述：允许空值
//**********************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Runtime.InteropServices;
using System.ComponentModel;
using System.Text.RegularExpressions;

namespace Hmc.IM.Common.UserControls
{
    /// <summary>
    /// 自定义时间控件
    /// </summary>
    [ToolboxBitmap(typeof(System.Windows.Forms.DateTimePicker))]
    public class ucDateTimePicker : DateTimePicker, IValidate
    {
        #region ComboInfoHelper
        internal class ComboInfoHelper
        {

            public static int GetComboDropDownWidth()
            {
                ComboBox cb = new ComboBox();
                //DateTimePicker cb = new DateTimePicker();
                int width = GetComboDropDownWidth(cb.Handle);
                cb.Dispose();
                return width;
            }
            public static int GetComboDropDownWidth(IntPtr handle)
            {
                NativeMethods.ComboBoxInfo cbi = new NativeMethods.ComboBoxInfo();
                cbi.cbSize = Marshal.SizeOf(cbi);
                NativeMethods.GetComboBoxInfo(handle, ref cbi);
                int width = cbi.rcButton.Right - cbi.rcButton.Left;
                return width;
            }
        }
        #endregion

        [DllImport("user32.dll", EntryPoint="SendMessageA")]
        private static extern int SendMessage (IntPtr hwnd, int wMsg, IntPtr wParam, int lParam);

        const int WM_ERASEBKGND = 0x14;
        const int WM_NC_HITTEST = 0x84;
        const int WM_NC_PAINT = 0x85;
        const int WM_PRINTCLIENT = 0x318;
        const int WM_SETCURSOR = 0x20;

        /// <summary>
        /// 热点颜色
        /// </summary>
        private Pen BorderPen = new Pen(Color.FromArgb(0x33, 0x5E, 0xA8), 1);
        /// <summary>
        /// 边框颜色
        /// </summary>
        private Pen BorderPenControl = new Pen(Color.FromArgb(219, 224, 230), 1);
        private bool DroppedDown = false;
        //private int InvalidateSince = 0;
        private static int DropDownButtonWidth = 17;

        /// <summary>
        /// 错误提示信息
        /// </summary>
        ucErrorProvider errorInfo = new ucErrorProvider();

        static ucDateTimePicker()
        {
            // 2 pixel extra is for the 3D border around the pulldown button on the left and right
            DropDownButtonWidth = ComboInfoHelper.GetComboDropDownWidth()+2 ;    
        }
        /// <summary>
        /// 
        /// </summary>
        public ucDateTimePicker()
            : base()
        {
            this.SetStyle(ControlStyles.DoubleBuffer, true);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventargs"></param>
        protected override void OnValueChanged(EventArgs eventargs)
        {
            base.OnValueChanged (eventargs);
            this.Invalidate();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            IntPtr hDC = NativeMethods.GetWindowDC(m.HWnd);
            Graphics gdc = Graphics.FromHdc(hDC);
            switch (m.Msg)
            {
                case WM_NC_PAINT:
                    SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
                    SendPrintClientMsg();
                    SendMessage(this.Handle, NativeMethods.WM_PAINT, IntPtr.Zero, 0);
                    OverrideControlBorder(gdc);

                    m.Result = (IntPtr)1; // indicate msg has been processed
                    break;
                case NativeMethods.WM_PAINT: base.WndProc(ref m);
                    OverrideControlBorder(gdc);
                    OverrideDropDown(gdc);
                    break;
                case WM_NC_HITTEST:
                    base.WndProc(ref m);
                    if (DroppedDown)
                        this.Invalidate(this.ClientRectangle, false);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
            NativeMethods.ReleaseDC(m.HWnd, hDC);
            gdc.Dispose();    

            
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ctrl"></param>
        /// <param name="g"></param>
        public static void PaintFlatDropDown(Control ctrl, Graphics g)
        {
            Rectangle rect = new Rectangle(ctrl.Width - DropDownButtonWidth, 0, DropDownButtonWidth, ctrl.Height);
            ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);
        }
        private void SendPrintClientMsg()
        {
            // 我们把这条消息控制重绘窗口到客户区
            Graphics gClient = this.CreateGraphics();
            IntPtr ptrClientDC = gClient.GetHdc();
            SendMessage(this.Handle, WM_PRINTCLIENT, ptrClientDC, 0);
            gClient.ReleaseHdc(ptrClientDC);
            gClient.Dispose();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="text"></param>
        public void SetText(string text)
        {
            if (text != "")
            {
                this.Format = DateTimePickerFormat.Long;

                this.Text = text;
            }
            else
            {
                this.Format = DateTimePickerFormat.Custom;
            }
        }

        private void OverrideDropDown(Graphics g)
        {
            if (!this.ShowUpDown)
            {
                //Rectangle rect = new Rectangle(this.Width-DropDownButtonWidth, 0, DropDownButtonWidth, this.Height);
                //ControlPaint.DrawComboButton(g, rect, ButtonState.Flat);    
            }
        }

        /// <summary>
        /// 重写控件边框
        /// </summary>
        /// <param name="g"></param>
        private void OverrideControlBorder(Graphics g)
        {

            if (this.Focused == false || this.Enabled == false )
                g.DrawRectangle(BorderPenControl, new Rectangle(0, 0, this.Width, this.Height));
            else
                g.DrawRectangle(BorderPen, new Rectangle(0, 0, this.Width, this.Height));
        }
        /// <summary>
        /// 按下特定键
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyUp(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Back || e.KeyCode == Keys.Delete)
            {
                this.Format = DateTimePickerFormat.Custom;
                this.CustomFormat = " ";
            }
            base.OnKeyUp(e);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventargs"></param>
        protected override void OnDropDown(EventArgs eventargs)
        {
            //InvalidateSince = 0;
            DroppedDown = true;
            base.OnDropDown (eventargs);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventargs"></param>
        protected override void OnCloseUp(EventArgs eventargs)
        {
            DroppedDown = false;
            if (this.Format == DateTimePickerFormat.Custom && this.CustomFormat.Trim() == string.Empty)
                this.CustomFormat = "yyyy-MM-dd";
            base.OnCloseUp (eventargs);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLostFocus(System.EventArgs e)
        {
            base.OnLostFocus(e);
            this.Invalidate();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnGotFocus(System.EventArgs e)
        {
            base.OnGotFocus(e);
            this.Invalidate();
        }       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnResize(EventArgs e)
        {
            base.OnResize (e);
            this.Invalidate();
        }



        #region 实现IUserControl接口方法

        private bool isAllowEmpty = true;

        /// <summary>
        /// 设置是否允许为空
        /// </summary>
        [Browsable(true), Category("验证"), DefaultValue(true), Description("设置控件的值是否允许为空")]
        public bool IsAllowEmpty
        {
            get { return isAllowEmpty; }
            set { isAllowEmpty = value; }
        }

        /// <summary>
        /// 验证
        /// </summary>
        /// <returns></returns>
        public bool Validate()
        {
            errorInfo.Clear();
            if (!this.IsAllowEmpty)
            {
                if ((this.Value == DateTime.MaxValue) || (this.Value == DateTime.MinValue) || (this.Text.Trim() == string.Empty))
                {
                    errorInfo.SetError(this, "该项不能为空！");
                    return this.IsValidated = false;
                }
            }
            if ((this.Expression != null) && (this.Expression.Trim() != string.Empty)
                && (!Regex.IsMatch(this.Value.ToString(), this.Expression)))
            {
                errorInfo.SetError(this, this.SetError);
                return this.IsValidated = false;
            }
            return this.IsValidated = true;
        }

        /// <summary>
        /// 验证是否通过
        /// </summary>
        [Browsable(false), Category("验证"), Description("获取该控件是否已验证通过")]
        public bool IsValidated
        {
            get;
            set;
        }

        /// <summary>
        /// 设置与内容匹配的正则表达式
        /// </summary>
        [Browsable(true), Category("验证"), Description("设置要匹配的正则表达式")]
        public string Expression
        {
            get;
            set;
        }

        /// <summary>
        /// 设置验证不通过的错误提示信息
        /// </summary>
        [Browsable(true), Category("验证"), Description("设置验证未通过时提示的内容")]
        public string SetError
        {
            get;
            set;
        }

        #endregion

        /// <summary>
        /// 重写验证事件
        /// </summary>
        /// <param name="e"></param>
        protected override void OnValidating(CancelEventArgs e)
        {
            Validate();
            base.OnValidating(e);
        }
    }
}
